<?php

namespace tools\lib\main\controller;

use tools\lib\main\Common;

class Swagger extends Common
{

    protected $suffix = false;

    /**
     * 保存的文件名称
     * @return string
     */
    protected function saveName()
    {
        return $this->parameter->getAction() . '.json';
    }

    /**
     * @return string
     */
    protected function savePath()
    {
        return rtrim($this->getFileDirectory(), '/') . '/' . $this->saveName();
    }

    /**
     * 初始化
     */
    protected function init()
    {
        parent::init();

        $this->setConfig('doc');

        /**
         * 修正文件保存路径
         */
        $this->setFileDirectory('module_directory');

        /**
         * 创建 ./doc/common/definitions
         */
        $this->checkCommonDefinitions();

        /**
         * 创建模块下的 base.json
         */
        $this->checkModuleBaseJson();

        /**
         * 创建访问接口文档的控制器
         */
        $this->checkRequestController();
    }

    /**
     * 路径：document/模块/paths/控制器名称/api.json
     * @return string
     */
    public function template()
    {
        if (empty($this->parameter->getAction())) {
            return false;
        }

        $this->getProperties($parameters, $response_data);

        if ($parameters) {
            $parameters = rtrim(rtrim($parameters, "\n"), ',') . "\n";
            $parameters = '[' . "\n" . $parameters . '      ]';
        } else {
            $parameters = '[]';
        }

        $request = transToPascal($this->parameter->getName()) . '/' . $this->parameter->getAction();


        $template = $this->getTemplate("/$request",
            $parameters,
            $response_data = str_replace('\/', '/', json_encode($response_data, JSON_UNESCAPED_UNICODE)),
            $this->parameter->getSummary(),
            $this->parameter->getDescription()
        );

        return $template;
    }

    /**
     * @param $request
     * @param array $parameters
     * @param null $response_data
     * @param string $summary
     * @param string $description
     * @return string
     */
    private function getTemplate($request, $parameters = [], $response_data = null, $summary = '', $description = '')
    {
        $template = <<<EOF
{
  "$request": {
    "post": {
      "summary": "$summary",
      "description": "$description",
      "consumes": [
        "application/x-www-form-urlencoded"
      ],
      "produces": [
        "application/json"
      ],
      "parameters": $parameters,
      "responses": {
        "200": {
          "type": "object",
          "properties": {
            "code": {
               "\$ref": "#/definitions/code"
            },
            "msg": {
              "\$ref": "#/definitions/msg"
            },
            "data": 
              $response_data
          }
        }
      }
    }
  }
}
EOF;

        return $template;
    }

    /**
     * 组装参数
     * @param string $name
     * @param string $description
     * @param string $type
     * @param bool $required
     * @param string $in
     * @return array
     */
    private function concatParametersArray($name, $description, $type = 'string', $required = false, $in = 'formData')
    {
        return [
            'in' => $in,
            'name' => $name,
            'type' => $type,
            'required' => $required,
            'description' => $description
        ];
    }

    /**
     * @param $name
     * @param $description
     * @param string $type
     * @param bool $required
     * @param string $in
     * @return string
     */
    private function concatParametersString($name, $description, $type = 'string', $required = true, $in = 'formData')
    {
        $result = '        {' . "\n"
            . '          "in": "' . $in . '",' . "\n"
            . '          "name": "' . $name . '",' . "\n"
            . '          "type": "' . $type . '",' . "\n"
            . '          "required": ' . ($required ? 'true' : 'false') . ',' . "\n"
            . '          "description": "' . $description . '"' . "\n"
            . '        },' . "\n";

        return $result;
    }

    /**
     * @param array $parameters
     * @param array $response_data
     */
    private function getProperties(&$parameters = [], &$response_data = [])
    {
        /**
         * 传递的参数信息,是一个数组,键是参数名称,值是默认值,这里不需要默认值,修改正描述信息即可
         */
        $params = $this->parameter->getParams();

        $properties = [];
        foreach ($params as $key => $item) {

            $type = 'string';

            if (in_array($key, ['id', 'create_time', 'sort', 'status', 'type',])) {
                $type = 'integer';
            }

            $properties[$key] = [
                'type' => $type,
                'description' => $item
            ];
            $params[$key] = $this->concatParametersArray($key, '', $type);
        }

        /**
         * 列表页自动添加分页参数
         */
        if (preg_match('/list|List/', $this->parameter->getAction())) {

            array_unshift(
                $params,
                ' "$ref": "#/definitions/page_id"'
            );

            array_unshift(
                $params,
                ' "$ref": "#/definitions/page_size"'
            );

            $response_data = [
                'type' => 'object',
                'properties' => [
                    'pages' => [
                        '$ref' => '#/definitions/pages'
                    ],
                    'list' => [
                        'type' => 'array',
                        'items' => [
                            'properties' => $properties
                        ]
                    ]
                ],
            ];
        } elseif (preg_match('/info|Info/', $this->parameter->getAction())) {
            $response_data = [
                'type' => 'object',
                'properties' => $properties,
            ];
        } else {
            $response_data = "";
        }

        $result = '';
        if ($params) {
            foreach ($params as $item) {
                if (isset($item['name'])) {
                    $result .= $this->concatParametersString($item['name'], $item['description'], $item['type'], $item['required'], $item['in']);
                } else {
                    $result .= '        {' . "\n"
                        . '         ' . $item . "\n"
                        . '        },' . "\n";
                }
            }
        }

        $parameters = $result;
    }

    /**
     * 获取文档的地址
     *  document/
     *  doc/
     * @return bool|string
     */
    private function docBasePath()
    {
        $docBasePath = $this->config['base_directory'];

        /**
         * 如果接口文档的路径不存在，则创建
         */
        if (!checkAndCreateDirectory($docBasePath)) {
            dump('接口文件基础路径创建错误,请检查' . $docBasePath);
            return false;
        };

        return $docBasePath;
    }

    /**
     * 路径：document/模块/
     * @return string
     */
    public function modulePath()
    {
        $docBasePath = $this->docBasePath();

        $module_path = $docBasePath . $this->parameter->getModule() . '/';

        checkAndCreateDirectory($module_path);

        return $module_path;
    }

    /**
     * @param $docBasePath
     * @return bool|int
     */
    private function checkCommonDefinitions($docBasePath = '')
    {
        if (empty($docBasePath)) {
            $docBasePath = $this->docBasePath();
        }

        // 检测公共目录
        $common_path = $docBasePath . 'common/';

        if (!checkAndCreateDirectory($common_path)) {
            dump('创建目录失败,请检查 : ' . $common_path);
            return false;
        };

        // 检测 common/definitions
        $definitions_path = $common_path . 'definitions/';
        if (!checkAndCreateDirectory($definitions_path)) {
            dump('创建目录失败,请检查 : ' . $definitions_path);
            return false;
        };

        // 检测 common/paths
        $paths_path = $common_path . 'paths/';
        if (!checkAndCreateDirectory($paths_path)) {
            dump('创建目录失败,请检查 :' . $paths_path);
            return false;
        };

        // 创建 definitions 下的 code  msg  page信息
        $json = [
            'code' => [
                'type' => 'integer',
                'description' => '错误代码'
            ],
            'msg' => [
                'type' => 'string',
                'description' => '返回的信息'
            ],
            'pages' => [
                'type' => 'object',
                'description' => '分页参数',
                'properties' => [
                    'total' => [
                        'type' => 'integer',
                        'description' => '总数'
                    ],
                    'per_page' => [
                        'type' => 'integer',
                        'description' => '每页数量'
                    ],
                    'current_page' => [
                        'type' => 'integer',
                        'description' => '当前页码'
                    ],
                    'last_page' => [
                        'type' => 'integer',
                        'description' => '最后一页页码'
                    ],
                    'has_more' => [
                        'type' => 'integer',
                        'description' => '是否还有更多 0 没有 1 有'
                    ],
                ]
            ]
        ];

        foreach ($json as $key => $item) {
            $json_file_name = $definitions_path . $key . '.json';
            if (!is_file($json_file_name)) {
                return file_put_contents($json_file_name, json_encode([$key => $item], JSON_UNESCAPED_UNICODE));
            }
        }

        return true;
    }

    /**
     * 路径：document/模块/base.json
     * @return string
     */
    private function checkModuleBaseJson()
    {
        $module_path = $this->modulePath();

        $base_api_json = $module_path . 'main.json';

        $module = $this->parameter->getModule();

        $host = '127.0.0.1';

        if (is_file($base_api_json)) {
            return true;
        }

        $template = <<<ETO
{
  "swagger": "2.0",
  "info": {
    "title": "$module api 接口文档",
    "description": "",
    "version": "1.0.0"
  },
  "host": "$host",
  "basePath": "/$module/",
  "schemes": [
    "http",
    "https"
  ],
  "tags": [
    {
      "name": "basic",
      "description": "获取ticket"
    }
  ]
}
ETO;
        file_put_contents($base_api_json, $template);
        return true;
    }

    /**
     * 创建访问接口文档访问的控制器
     * @return bool
     */
    private function checkRequestController()
    {
        $doc_path = $this->config['request_controller'];

        if (!checkAndCreateDirectory($doc_path)) {
            dump('创建接口访问控制器失败');
        };

        $file_path = $doc_path . 'Index.php';

        if (is_file($file_path)) {
            return true;
        }

        $template = <<<ETO
<?php

namespace app\doc\controller;

use SwaggerApi\Api;
use think\Request;

class Index
{
    public function index()
    {
        \$swagger = new Api();

        \$doc_name = Request::instance()->param('doc_name');

        return \$swagger->display(url('getJson', ['doc_name' => \$doc_name]));
    }

    public function getJson()
    {
        \$doc_name = Request::instance()->param('doc_name');

        \$swagger = new Api();

        \$docBasePath = '.{$this->docBasePath()}';

        echo \$swagger->getJson(\$docBasePath, \$doc_name);
    }
}
ETO;

        if (file_put_contents($file_path, $template)) {
            return true;
        }

        return false;
    }
}